package square;

import dungeon.Position;
import be.kuleuven.cs.som.annotate.Immutable;

/**
 * An enumeration introducing different directions.
 * 		In its current form, the class only supports 
 * 		North, South, East, West, Floor and Ceiling
 * 
 * @version 2.0
 * @author Inge Gielis <inge.gielis@student.kuleuven.be>
 * @author Annelies Ketelslegers <annelies.ketelslegers@student.kuleuven.be>
 */
public enum Direction {
	
	NORTH {
		
		/**
		 * Return the direction that is opposite to NORTH.
		 * 
		 * @return	The direction SOUTH
		 * 			| result == SOUTH
		 */
		@Immutable
		public Direction getOpposite(){
			return SOUTH;}
		
		/**
		 * Return the position next to the given position, in the direction NORTH.
		 * 
		 * @return 	Null if the given position is not effective or if the 
		 * 			Y-coordinate of the given position is 0.
		 * 			|if(position == null || position.getY()==0)
		 *			|		then result == null
		 * @return	The position next to the given position in the direction NORTH
		 * 			|result == new Position(position.getX(), position.getY()-1, position.getZ())
		 */
		public Position goStepInDirection(Position position){
			if(position == null || position.getY()==0)
				return null;
			return new Position(position.getX(), position.getY()-1, position.getZ());
		}
	}, 
	EAST{
		
		/**
		 * Return the direction that is opposite to EAST.
		 * 
		 * @return	The direction WEST
		 * 			| result == WEST
		 */
		@Immutable
		public Direction getOpposite(){
			return WEST;}
		
		/**
		 * Return the position next to the given position in the direction EAST.
		 * 
		 * @return 	Null if the given position is not effective 
		 * 			|if(position == null) 
		 *			|		then result == null
		 * @return	The position next to the given position in the direction EAST
		 * 			|result == new Position(position.getX()+1, position.getY(), position.getZ())
		 */
		public Position goStepInDirection(Position position){
			if(position == null)
				return null;
			return new Position(position.getX()+1, position.getY(), position.getZ());
		}}, 
	SOUTH{
		
		/**
		 * Return the direction that is opposite to SOUTH.
		 * 
		 * @return	The direction NORTH
		 * 			| result == NORTH
		 */
		@Immutable
		public Direction getOpposite(){
			return NORTH;}
		
		/**
		 * Return the position next to the given position in the direction SOUTH.
		 * 
		 * @return 	Null if the given position is not effective 
		 * 			|if(position == null) 
		 *			|		then result == null
		 * @ return	The position next to the given position in the direction SOUTH
		 * 			|result == new Position(position.getX(), position.getY()+1, position.getZ())
		 */
		public Position goStepInDirection(Position position){
			if(position == null)
				return null;
			return new Position(position.getX(), position.getY()+1, position.getZ());
		}}, 
	WEST{
			
		/**
		 * Return the direction that is opposite to WEST.
		 * 
		 * @return	The direction EAST
		 * 			| result == EAST
		 */	
		@Immutable
		public Direction getOpposite(){
			return EAST;}
		
		/**
		 * Return the position next to the given position in the direction WEST.
		 * 
		 * @return 	Null if the given position is not effective or if the 
		 * 			X-coordinate of the given position is 0.
		 * 			|if(position == null || position.getX()==0)
		 *			|		then result == null
		 * @return	The position next to the given position in the direction WEST
		 * 			|result == new Position(position.getX()-1, position.getY(), position.getZ())
		 */
		public Position goStepInDirection(Position position){
			if(position == null || position.getX() == 0)
				return null;
			return new Position(position.getX()-1, position.getY(), position.getZ());
		}}, 
	CEILING{
			
		/**
		 * Return the direction that is opposite to CEILING.
		 * 
		 * @return	The direction FLOOR
		 * 			| result == FLOOR
		 */
		@Immutable
		public Direction getOpposite(){
			return FLOOR;}
		
		/**
		 * Return the position next to the given position in the direction CEILING.
		 * 
		 * @return 	Null if the given position is not effective 
		 * 			|if(position == null) 
		 *			|		then result == null
		 * @return	The position next to the given position in the direction CEILING
		 * 			|result == new Position(position.getX(), position.getY(), position.getZ()+1)
		 */
		public Position goStepInDirection(Position position){
			if(position == null)
				return null;
			return new Position(position.getX(), position.getY(), position.getZ()+1);
		}}, 
		
	FLOOR{
		
		/**
		 * Return the direction that is opposite to FLOOR.
		 * 
		 * @return	The direction CEILING
		 * 			| result == CEILING
		 */
		@Immutable
		public Direction getOpposite(){
			return CEILING;}
		
		/**
		 * Return the position next to the given position in the direction FLOOR.
		 * 
		 * @return 	Null if the given position is not effective or if the 
		 * 			Z-coordinate of the given position is 0.
		 * 			|if(position == null || position.getZ()==0)
		 *			|		then result == null
		 * @return	The position next to the given position in the direction FLOOR
		 * 			|result == new Position(position.getX(), position.getY(), position.getZ()-1)
		 */
		public Position goStepInDirection(Position position){
			if(position == null || position.getZ() == 0)
				return null;
			return new Position(position.getX(), position.getY(), position.getZ()-1);
		}};
	
		
	/**
	 * Return the opposite direction of this direction.
	 */
	@Immutable
	public abstract Direction getOpposite();
	
	/**
	 * Return the position next to the given position in this direction.
	 */
	public abstract Position goStepInDirection(Position position);

}
